import numpy as np
import random
import os
import sys
import matplotlib.pyplot as plt
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname("__file__"), '..')))
from agentDesign.L1.read_map import AStarPlanner, ReadMap

# 时间设计
ONE_DAY = 360
ONE_HOUR = 30
# 订单的倍数
n = 0.05
read_map = ReadMap()
merchant_list = read_map.get_door("饭店")[0:21]
rest_list = read_map.get_door("公司")

#划分区域
region_one = [[0, 0], [102, 0], [0, 42], [102, 42]]
region_two = [[0, 43], [102, 43], [0, 77], [102, 77]]
region_three = [[0, 77], [102, 77], [0, 107], [102, 107]]
Region_info = [[(0, 0), (0, 200), (18, 0), (18, 200)],  # 公司
               [(120, 0), (56, 0), (120, 200), (56, 200)],
               [(121, 66), (300, 66), (121, 107), (300, 107)],
               [(396, 66), (300, 66), (300, 107), (396, 107)],
               [(396, 107), (396, 200), (331, 200), (331, 107)],
               [(18, 0), (56, 0), (18, 200), (56, 200)],  # 饭店
               [(331, 107), (121, 107), (331, 139), (121, 139)],
               [(331, 139), (121, 139), (331, 200), (121, 200)],
               [(121, 0), (396, 0), (121, 66), (396, 66)],
               [(430, 0), (430, 200), (396, 0), (396, 200)]]
order_match_region = {"A": 0, "B": 1, "C": 2, "D": 3}
#  饭店地质
rest_one = [ (91, 59), (64, 50),
             ]
rest_two = [(366, 81)]
rest_three = [(345, 140), (350, 131), (358, 110), (338, 110), (377, 140), (393, 75), (393, 87), (298, 95), (15, 15), (15, 23), (53, 62), (53, 56), (53, 98), (39, 103), (38, 13), (41, 71), (26, 99), (26, 92), (26, 23), (320, 110), (298, 148), (380, 63), (310, 131)]

#  公司地质
home_list = [[(15, 15), (15, 23), (15, 30), (15, 136), (15, 144)],
             [(64, 50), (64, 58), (77, 71), (86, 47), (91, 59)],
             [(293, 73), (298, 85), (298, 95)],
             [(348, 73), (350, 100), (372, 73), (378, 100), (387, 100), (393, 75), (393, 83), (393, 87)],
             [(336, 119), (338, 110), (342, 131), (345, 140), (349, 110), (350, 131), (354, 131), (358, 110),
              (362, 140), (373, 110), (377, 140), (382, 131), (388, 140)]]
restaurant_list = [[(26, 23), (26, 92), (26, 99), (38, 13), (38, 47), (39, 103), (41, 71), (42, 37), (53, 98), (53, 24),  (53, 62), (53, 56)],
                   [(310, 131), (320, 110), (320, 131)],
                   [(298, 148), (315, 140)],
                   [(357, 63), (380, 63)],
                   [(416, 140)]]
home_one = [ (64, 58), (77, 71), (86, 47)]
home_two = [(372, 73), (378, 100), (387, 100),
            (349, 110), (373, 110), (336, 119), (342, 131), (354, 131), (382, 131),
            (388, 140)]
home_three = [(350, 100), (348, 73), (362, 140), (393, 83), (293, 73), (298, 85), (15, 30), (15, 136), (15, 144), (53, 24), (42, 37), (38, 47), (320, 131), (357, 63), (416, 140), (315, 140)]
#  比例
weight = {"A": 0.2, "B": 0.2, "C": 0.2, "D": 0.2, "E": 0.2}


def point_in_rectangle(rectangle, point):
    # 矩形的四个顶点坐标
    x1, y1 = rectangle[0]
    x2, y2 = rectangle[1]
    x3, y3 = rectangle[2]
    x4, y4 = rectangle[3]
    x_min = min(x1, x2, x3, x4)
    x_max = max(x1, x2, x3, x4)
    y_min = min(y1, y2, y3, y4)
    y_max = max(y1, y2, y3, y4)
    # 检查点的 x 坐标是否在矩形的左右边界之间
    if int(x_min) <= int(point[0]) <= int(x_max):
        # 检查点的 y 坐标是否在矩形的上下边界之间
        if int(y_min) <= int(point[1]) <= int(y_max):
            return True

    return False


def get_which_region(position):
    # 获取属于的region
    node = position
    # 返回前往的区域编号
    for index, region in enumerate(Region_info):
        if point_in_rectangle(region, node):
            return index
    return 0

def check():
    eat_one = []
    eat_two = []
    eat_three = []
    for node in rest_list:
        if node[0][1] <= 42:
            eat_one.append(node[0])
        elif node[0][1] >= 77:
            eat_three.append(node[0])
        else:
            eat_two.append(node[0])
    print(eat_one)
    print(eat_two)
    print(eat_three)


def get_n():
    return n

def data_list(time_num, BF, prob_region, prob_time):  # 输入模拟订单时长的时间长度，返回数组每个时间段的订单长度
    """_summary_

    Args:
        time_num (_type_): 时间长度
        BF (_type_): 波峰数量
        prob_region (_type_): 每个区域的订单数量调整参数 0-1
        prob_time (_type_): 每个区域的时间差 0-360

    Returns:
        _type_: 字典 每个区域的订单数量
    """
    regions_name = [ "A", "B", "C", "D", "E"]
    ans_list = {"A": [], "B": [], "C": [], "D": [], "E": []}
    for i in range(time_num):
        for region_name in regions_name: 
            tmp_data = fitting_dist(((i - prob_time[region_name]) % 360) * BF * prob_region[region_name])
            ans_list[region_name].append(int(tmp_data))
        # if i < 100:
        #     ans_list["A"] = 100
        # elif i < 200:
        #     ans_list["B"] = 100
        # else:
        #     ans_list["C"] = 100
    return ans_list

# 订单产生的函数
def fitting_dist(x):
    a = [314.2, 188.3, 95.56, 22.9, 48.67]
    b = [172.5, 281.5, 315.5, 228.9, 267.1]
    c = [4.645, 1.559, 10.69, 167.7, 13.1]
    fitting_model = 0
    for i in range(0, 5):
        fitting_model = fitting_model + a[i] * np.exp(-((x - b[i]) / c[i]) ** 2)
    return fitting_model


# 订单类型函数，订单的类型有A, B, C, A正常，B高峰期，C配送费用高
# A: 订单从第一个商圈获得订单，订单价格低
# B：订单从第二个商圈获得，订单价格高
# C：订单从第三个商圈中获得，订单价格高同时距离偏远
def get_order_type():
    return random.choices(list(weight.keys()), weights=list(weight.values()), k=1)[0]


# 订单难度，1/2/3
def order_difficulty():
    return random.randint(1, 3)


# 订单是否支持合作,0/1
def order_cooperation():
    return random.randint(0, 1)


# 订单金额
def order_money(order_type, merchant_node, rest_node, time_runner, high_quality=False):
    # 金额由time dis order三个要素决定
    dis = merchant_rest_dis(merchant_node, rest_node) / 10  # 实际距离除以10
    money_dis = 3.7 + (dis - 30) * 0.1 if dis > 30 else 3.7
    money_time = 0
    if time_runner <= 2 * ONE_HOUR:
        money_time += 0.5
    elif time_runner <= 6 * ONE_HOUR:
        money_time += 1
    elif time_runner > 22 * ONE_HOUR:
        money_time += 0.3

  # 根据是否是高质量订单，调整订单金额
    if high_quality:
        return (random.uniform(0, 20) * 0.13 + money_dis + money_time) * 1.2  # 假设高质量订单金额增加20%
    else:
        return random.uniform(0, 20) * 0.13 + money_dis + money_time


# 订单处理成本
def order_process():
    return random.randint(20, 50)


# !!!修改：订单位置-商家
def merchant_position(order_type):
    random_node = random.choice(list(restaurant_list[ord(order_type) - ord('A')]))
    return random_node


#  !!!增加：计算距离的公式
def merchant_rest_dis(merchant_pos, rest_pos):
    return ((merchant_pos[0] - rest_pos[0]) ** 2 +
            (merchant_pos[1] - rest_pos[1]) ** 2) ** 0.5


#  !!!修改：订单位置-目的地
def rest_position(order_type):
    random_node = random.choice(list(home_list[ord(order_type)- ord("A")]))
    return random_node


# 订单位置-随机选择
def order_position(G):
    random_node = random.choice(list(G))
    return random_node


# 生成单日订单序列,单日订单序列是由列表组成，列表的每一个元素为一个订单list，
# 例：[['AC', 76, 17, 2, pos], ['C', 30, 17, 1,pos], ['AB', 48, 17, 2, pos]]
def orders_list(order_num, time_runner, order_type, high_quality=False):
    daily_order = []
    for i in range(order_num):
        merchant_pos = merchant_position(order_type)
        rest_pos = rest_position(order_type)
        order_money_amount = order_money(order_type, merchant_pos, rest_pos, time_runner, high_quality)
        daily_order.append([random.choice([get_which_region(rest_pos), get_which_region(merchant_pos)]),
                            order_money_amount,
                            merchant_pos,
                            rest_pos,
                            order_difficulty(),
                            high_quality])  # 在订单列表中加入高质量标识
    return daily_order




# 生成365天订单，生成的为订单列表，列表中的每一个元素为一个单日订单列表
def all_orders_list(G, rand=True):
    # 目前生成的订单数量是针对两家企业产生的，如果订单的数量觉得不够的话可以修改n的大小，让订单成倍增长
    if not rand:
        random.seed(0)
    all_list = []
    for i in range(1, 1000):
        i = (i % 150) * 3  # 调节波峰出现速率 | 取余，每150循环一遍
        order_num = int(n * int(fitting_dist(i)))
        orders = orders_list(order_num)

        for order in orders:
            order.append(i)
        all_list.append(orders)

    return all_list


if __name__ == "__main__":

    # G = [1, 2, 3]
    # rand = True
    # if not rand:
    #     random.seed(0)
    # all_list = []
    # nums = 0
    # for i in range(1, 300):
    #     # i = (i % 120) * 3  # 调节波峰出现速率 | 取余，每150循环一遍
    #     order_number = int(0.03 * int(fitting_dist(((i - 25) % 80) * 3)))
    #     orders = orders_list(order_number, i, 'A')
    #     nums += len(orders)
    #     print(i, orders)
    # print("the final len: ", nums)

    prob_time = {
        "A": 5,
        "B": 25,
        "C": 55,
        "D": 85,
        "E": 60 # 五个商区的信息
    }
    prob_region = {
        "A": 0.02,
        "B": 0.03,
        "C": 0.04,
        "D": 0.04,
        "E": 0.04 # 五个商区的信息
    }
    ans_list = data_list(200, 3, prob_region, prob_time)
    print(ans_list)
    # 准备数据，创建索引号
    indexes = list(range(len(ans_list[next(iter(ans_list))])))  # 假设所有数组长度相同

    # 创建图形和轴
    fig, ax = plt.subplots()

    # 绘制每个数组的变化曲线
    for key, values in ans_list.items():
        ax.plot(indexes, values, label=key)

    # 添加图例
    ax.legend()

    # 添加标题和轴标签
    ax.set_title('变化曲线图')
    ax.set_xlabel('索引号')
    ax.set_ylabel('值')

    plt.savefig('curves.png')

    # 关闭图形，释放资源
    plt.close()
